var sys = require('sys'),
    net = require('net'),
    Amqp = require('../amqp'),
    DEFAULT_PROVIDER = 'rabbitmq';
function Stream_OnConnect(){
    this.write('AMQP' + String.fromCharCode(1, 1, Amqp.Version.Major, Amqp.Version.Minor));
}
/**
 *
 * @class
 * @extends handlers.Abstract
 * @exports Connection as handlers.Connection
 */
function Connection(){
    var connection = this, buffer = undefined;
    this.stream = new net.Stream();
    this.stream.addListener('connect', Stream_OnConnect);
    this.stream.addListener('data', function(/**Buffer*/data){
        var buffer = buffer, connection = connection, Amqp = Amqp;
        if (undefined == buffer) {
            buffer = data;
        } else {
            data.copy(buffer, buffer.length, 0, data.length - 1);
        }
        if (Amqp.Const.FrameEnd != data[data.length - 1]) return;
        var frames = require('../providers/' + connection.provider + '/decoder').decode(buffer);
        for (var i = 0, l = frames.length; i < l; ++i) {
            if (!('method' in frames[i])) continue;
            if ('classId' in frames[i].method && 'methodId' in frames[i].method) {
                if (frames[i].channel) {
                    connection.emit('Amqp.Channel[' + frames[i].channel + ']', frames[i]);
                } else {
                    var classId = frames[i].method.classId, methodId = frames[i].method.methodId;
                    connection.emit('Amqp.' + Amqp.Class[classId] + '.' + Amqp.Class[classId][methodId], frames[i]);
                }
            }
        }
        buffer = undefined;
    });
}
sys.inherits(Connection, require('./abstract').Abstract);
/**
 * Define amqp provider.
 *
 * @type String
 */
Connection.prototype.provider = DEFAULT_PROVIDER;
/**
 * Connect to Amqp server.
 *
 * @param port
 * @param host
 */
Connection.prototype.connect = function(/**Number*/port,/**String*/host){
    this.stream.connect(port, host);
};
/**
 * Close connection to Amqp server.
 *
 * @return
 */
Connection.prototype.close = function(){
    this.stream.close();
};
/**
 * Write message frame to Amqp server.
 *
 * @param frame
 * @throws
 */
Connection.prototype.write = function(/**Object*/frame){
    var data;
    try {
        data = require('../providers/' + this.provider + '/encoder').encode(frame);
    } catch(e){
        if ('method' in frame && 'classId' in frame.method && 'methodId' in frame.method) {
            e.stack = 'FRAME ENCODE ERROR [' + Amqp.Class[frame.method.classId] + '.' +
                Amqp.Class[frame.method.classId][frame.method.methodId] + ']\n' +
                sys.inspect(frame, false, null) + '\n' + e.stack;
        }
        throw e;
    }
    if ('frameMax' in this && this.frameMax < data.length) {
        throw new Error('Frame length <' + data.length + '> is more than expected <' +
                this.frameMax + '>');
    }
//    if (Amqp.Const.FrameMinSize / 256 > data.length) {
//        throw new Error('Frame length <' + data.length + '> is less than <' +
//                Amqp.Const.FrameMinSize / 256 + '>');
//    }
    this.stream.write(data, 'binary');
};
exports.Connection = Connection;
